package com.blyat.xsoft.auth.restful.service.impl;

import com.blyat.xsoft.auth.restful.entity.Authority;
import com.blyat.xsoft.auth.restful.mapper.AuthorityMapper;
import com.blyat.xsoft.auth.restful.service.AuthorityService;
import com.blyat.xsoft.kernel.restful.service.CrudService;
import com.blyat.xsoft.kernel.restful.pagination.PageList;
import com.google.common.collect.Maps;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author syh
 * @date 2019/10/21
 **/
@Service
public class AuthorityServiceImpl extends CrudService<Authority, AuthorityMapper> implements AuthorityService {

    @Override
    public List<Authority> getAll() {
        return mapper.getAll();
    }

    @Override
    public List<Authority> getAuthorityTreeByUserId(String userId) {
        List<Authority> list = mapper.getByUserId(userId);
        return createMenuTree(Authority.ROOT, null, list.stream().collect(Collectors.groupingBy(Authority::getPid)));
    }

    @Override
    public List<Authority> getByUserId(String userId) {
        return mapper.getByUserId(userId);
    }

    @Override
    public List<Authority> getByClientId(String clientId) {
        return mapper.getByClientId(clientId);
    }

    private List<Authority> createMenuTree(String pid, Set<String> ids, Map<String, List<Authority>> map) {
        return Optional.ofNullable(map.get(pid)).orElseGet(() -> new ArrayList<>()).stream()
                .filter(m -> pid.equals(m.getPid()))
                .sorted(Comparator.comparing(Authority::getSort))
                .map(x -> {
                    Authority.Meta meta = new Authority.Meta();
                    meta.setTitle(x.getName());
                    meta.setIcon(x.getIcon());
                    meta.setNoCache(x.isNoCache());
                    x.setMeta(meta);
                    x.setChildren(createMenuTree(x.getId(), ids, map));
                    if (ids != null) ids.add(pid);
                    return x;
                }).collect(Collectors.toList());
    }

    @Override
    public PageList<Authority> findAllAuthTreeByPage(String query) {
        List<Authority> menuList = mapper.getByParams(Collections.singletonMap("query", query));
        if (menuList != null && !menuList.isEmpty()) {
            Map<String, List<Authority>> menuMap = menuList.stream().collect(Collectors.groupingBy(Authority::getPid));
            Set<String> ids = new HashSet<>();
            List<Authority> tree = createMenuTree(Authority.ROOT, ids, menuMap);
            List<String> noRootNodes = menuMap.keySet().stream().filter(m -> !ids.contains(m)).collect(Collectors.toList());
            noRootNodes.forEach(pid -> {
                if (menuMap.containsKey(pid)) {
                    tree.addAll(menuMap.get(pid));
                }
            });
            return new PageList<>(0, tree.size(), tree.size(), tree);

        }
        return new PageList<>(0, 0, 0, new ArrayList<>());
    }

    @Override
    public List<Map<String, Object>> getAuthTree(String query) {
        List<Authority> list = mapper.getByParams(Collections.singletonMap("query", query));
        return createComponentTree(Authority.ROOT, list.stream().collect(Collectors.groupingBy(Authority::getPid)));
    }

    @Override
    public List<Map<String, Object>> buildSelectTree(String pid) {
        List<Authority> list = mapper.getAuthorityByPid(pid);
        return createComponentTree(Authority.ROOT, list.stream().collect(Collectors.groupingBy(Authority::getPid)));
    }

    private List<Map<String, Object>> createComponentTree(String pid, Map<String, List<Authority>> map) {
        return Optional.ofNullable(map.get(pid)).orElseGet(() -> new ArrayList<>()).stream()
                .filter(m -> pid.equals(m.getPid()))
                .sorted(Comparator.comparing(Authority::getSort))
                .map(x -> {
                    Map<String, Object> menu = Maps.newHashMapWithExpectedSize(3);
                    menu.put("id", x.getId());
                    menu.put("label", x.getName());
                    if (map.containsKey(x.getId())) {
                        menu.put("children", createComponentTree(x.getId(), map));
                    }
                    return menu;
                }).collect(Collectors.toList());
    }

    @Override
    protected boolean beforeInsert(Authority authority) {
        // todo check exists
        if (Authority.ROOT.equals(authority.getPid())) {
            authority.setComponent("Layout");
        }
        return super.beforeInsert(authority);
    }
}
